package gameEngine;

import java.util.Scanner;

import exceptions.IncorrectInputException;
import exceptions.NullFieldException;

public class Player {
	
	private static final int DOT_COORDINATES_NUMBER = 2;
	private static final int MIN_PLAYER_NAME = 1;
	private String name;
	private String playerInput;
	private int score;
	
	Player(String name) throws IncorrectInputException{
		playerInput = " ";
		setName(name);
	}

	private void setName(String name) throws IncorrectInputException {
		if(name==null || name.length() < MIN_PLAYER_NAME)
			throw new IncorrectInputException("Bad player name.");
			this.name = name;
		
	}

	public int getScore() {
		return score;
	}

	public void increaseScore() {
		this.score++;
	}

	public String getName() {
		return name;
	}
	
	public String getPlayerInput() {
		return playerInput;
	}
	
	/**
	 * The main part of the game - connecting the Two Dots.
	 * @param row - Enter the row of the dot.
	 * @param col - Enter the column ot the dot.
	 * @param direction - Enter the direction that the line goes. ( u - up, r - right)
	 * @throws IncorrectInputException If the player tries to go off the board.
	 */
	public void connectWithLine(int row, int col, char direction) throws IncorrectInputException {
		Dot[][] gameField = GameField.gameField;
		
		//Validating parameters:
		
		if(row>gameField.length-1 || row<0 || col>gameField.length-1 || col<0 || (direction != 'u' && direction !='r'))
			throw new IncorrectInputException("You have entered a bad key");
		
			
		
		Dot playerSelectedDot = gameField[row][col];
		Line l = new Line(playerSelectedDot, this);

		/* Checks the direction from input, and throws exception if 
		 * player is trying to draw outside the board.
		 * Checks if there is already a line.
		 * If not - draw a line.
		 * 
		 * There is small code repeat - can fix later:
		 */
		if (direction == 'r') {
			if(col == gameField.length-1)
				throw new IncorrectInputException("You are playing out of board.");
			
			if(playerSelectedDot.getRightLine()==null){
				playerSelectedDot.setRightLine(l);
			}else{
				throw new IncorrectInputException("There is already a line.");
			}
			
			
		}
		if (direction == 'u') {
			if(row==0)
			throw new IncorrectInputException("You are playing out of board.");
			if(playerSelectedDot.getUpLine()==null){
				playerSelectedDot.setUpLine(l);
			}else{
				throw new IncorrectInputException("There is already a line.");
			}
			
		}

	}
	
	
	
	/**
	 * Reads the player input from console.
	 * @throws IncorrectInputException If the user input has illigal arguments.
	 */
	public String readAndProcessPlayerInput() throws IncorrectInputException{
		Scanner sc = new Scanner(System.in);
		this.playerInput = sc.nextLine();
		
		if(this.playerInput == null || this.playerInput.length()==0)
			throw new IncorrectInputException("Invalid player input.");
		
		char lineDirection = getLineDirectionInUserInput(this.playerInput);
		int[] dotCoordinates = getCoordinatesInUserInput(this.playerInput);
		
		String processedUserInput = dotCoordinates[0]+""+dotCoordinates[1]+""+lineDirection;
		return processedUserInput;
	}


	
	
	/**
	 * The method takes a String and finds the direction of the input line.
	 * If there is non - exception is thrown. If there are more characters 
	 * they are ignored.
	 * @param userInput
	 * @return char representing the direction - 'u' or 'r'
	 * @throws IncorrectInputException
	 */
	private char getLineDirectionInUserInput(String userInput) throws IncorrectInputException {
		char lineDirection = 0;
		/*Check for u's and r's. If there aren't any - throw exception.
		 */
		for(int i = 0;i< userInput.length();i++){
			if(userInput.charAt(i) == 'r'){
				lineDirection = 'r';
				break;
			}
			if(userInput.charAt(i) == 'u'){
				lineDirection = 'u';
				break;
			}
		}
		if(lineDirection!='u' && lineDirection!='r'){
			throw new IncorrectInputException("You must enter direction");
		}
		return lineDirection;
		
	}
	/**
	 * The method takes a String and finds the two integers representing
	 * a dot coordinate. If there are less than two numbers - exception is thrown.
	 * If there are more than two numbers - the last ones are ignored.
	 * 
	 * @param userInput
	 * @return array of two integers containing the dot coordinates.
	 * @throws IncorrectInputException
	 */
	private int[] getCoordinatesInUserInput(String userInput) throws IncorrectInputException {
		int numericSymbolsInInput=0;
		int[] dotCoordinates = new int[DOT_COORDINATES_NUMBER];
		
		//Run threw user input:
		for(int i = 0;i< userInput.length();i++){
			//Look for digits only:
			if(Character.isDigit(userInput.charAt(i))){
				//Save the digit to array:
				dotCoordinates[numericSymbolsInInput] = Character.getNumericValue(userInput.charAt(i));
				//Increase the variable containing numbers found:
				numericSymbolsInInput++;
				//If coordinates are found break to prevent from out of bounds writing.
				if(numericSymbolsInInput == DOT_COORDINATES_NUMBER){
					break;
				}
			}
		}
		//If there aren't any coordinates throw exception
		if(numericSymbolsInInput!=DOT_COORDINATES_NUMBER){
			throw new IncorrectInputException("There must be at least 2 coordinates.");
		}
		return dotCoordinates;
	}
	
	
	/**
	 * Insert the code that checks for squares HERE.
	 * @throws NullFieldException 
	 */
	public int returnNumberOfSquares(Dot playerEnteredDot, char lineDirection) throws NullFieldException{
		if(playerEnteredDot == null)
			throw new NullFieldException("The dot can't be null.");
		
		Dot currentDot = playerEnteredDot;
		int numberOfSquares = 0;
		
		
			try{
				Dot upperDot = GameField.gameField[currentDot.getDotRowCoordinate()-1][currentDot.getDotColCoordinate()];
				Dot rightDot = GameField.gameField[currentDot.getDotRowCoordinate()][currentDot.getDotColCoordinate()+1];
				if(checkForSquare(upperDot, currentDot, rightDot)){
					numberOfSquares++;
				}
			}catch(ArrayIndexOutOfBoundsException e){
				//No need to do anything. Just that the playerEnteredDot is 
				//at the outter part of the field and is trying to get dots that do not exsist.
			}
			
		if(lineDirection == 'r'){
			try{
				Dot downDot = GameField.gameField[currentDot.getDotRowCoordinate()+1][currentDot.getDotColCoordinate()];
				Dot downRightDot = GameField.gameField[currentDot.getDotRowCoordinate()+1][currentDot.getDotColCoordinate()+1];
				if(checkForSquare(currentDot, downDot, downRightDot)){
					numberOfSquares++;
				}
			}catch(ArrayIndexOutOfBoundsException e){
				//No need to do anything. Just that the playerEnteredDot is 
				//at the outter part of the field and is trying to get dots that do not exsist.
			}
		}
		if(lineDirection =='u'){				
			try{
				Dot leftDot = GameField.gameField[currentDot.getDotRowCoordinate()][currentDot.getDotColCoordinate()-1];
				Dot upperLeftDot = GameField.gameField[currentDot.getDotRowCoordinate()-1][currentDot.getDotColCoordinate()-1];
				if(checkForSquare(upperLeftDot,leftDot,currentDot)){
					numberOfSquares++;
				}
			}catch(ArrayIndexOutOfBoundsException e){
				//No need to do anything. Just that the playerEnteredDot is 
				//at the outter part of the field and is trying to get dots that do not exsist.
			}
		}
		return numberOfSquares;
	}
	/**
	 * This method checks for square base on 3 dots. If the dots have requred lines
	 * there is a square.
	 * @param topLeftDot
	 * @param bottomLeftDot
	 * @param bottomRightDot
	 * @return
	 */
	private boolean checkForSquare(Dot topLeftDot, Dot bottomLeftDot, Dot bottomRightDot){
		boolean hasSquare = true;
		
		if(topLeftDot.getRightLine()==null)
			hasSquare = false;
		if(bottomLeftDot.getRightLine() == null || bottomLeftDot.getUpLine() == null)
			hasSquare = false;
		if(bottomRightDot.getUpLine() == null)
			hasSquare = false;
		
		return hasSquare;
	}

}
